package org.grayrabbit.cloud.core.application;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

import org.apache.commons.lang.StringUtils;
import org.grayrabbit.cloud.core.beans.Creator;
import org.grayrabbit.cloud.core.beans.CreatorException;
import org.grayrabbit.cloud.core.biz.BizResult;
import org.grayrabbit.cloud.core.biz.ObjectProxyArgument;
import org.grayrabbit.cloud.core.biz.ProxyArgument;
import org.grayrabbit.cloud.core.biz.ServerUtility;
import org.grayrabbit.cloud.core.config.Configurator;
import org.grayrabbit.cloud.core.config.ConfiguratorException;
import org.grayrabbit.cloud.core.module.Module;
import org.grayrabbit.cloud.core.module.ModuleConstructException;
import org.grayrabbit.cloud.core.module.ModuleException;
import org.grayrabbit.cloud.core.module.NoSuchModuleException;
import org.grayrabbit.cloud.core.rpc.Argument;
import org.grayrabbit.cloud.core.rpc.Result;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
 * @author sys53
 * @version 1.0
 * @created 2011-6-21 15:58:51
 */
public abstract class Application<R, T extends Module<Result, Argument>> {
	private static final Logger logger = LoggerFactory.getLogger(Application.class);
	private Configurator context;
	private ConcurrentHashMap<String,List<T>> modules;
	private ConcurrentHashMap<String, AtomicInteger> indexes;

	public Application(Configurator context) {
		assert (context != null);
		
		this.context = context;
		this.modules = new ConcurrentHashMap<String,List<T>>();
		this.indexes = new ConcurrentHashMap<String, AtomicInteger>();
	}

	/**
	 * 
	 * @param moudle
	 * @param type
	 */
	public void add(T module, String type) {
		 assert ((type != null) && (module != null));
		  List<T> ms = getInitModules(type);
		   synchronized (ms) {
		     ms.add(module);
		   }
	}

	private List<T> getInitModules(String type) {
		List<T> ms = this.modules.get(type);
	     if (ms == null) {
	       ms = new ArrayList<T>();
	       AtomicInteger index = new AtomicInteger(0);
	       this.indexes.putIfAbsent(type, index);
	       this.modules.putIfAbsent(type, ms);
	       ms = this.modules.get(type);
	     }
	     return ms;
	}

	/**
	 * 
	 * @param moudle
	 * @param name
	 * @param type
	 */
	public void add(T module, String name, String type) {
		assert ((type != null) && (name != null) && (module != null));
		List<T> ms = getInitModules(type);
		synchronized (ms) {
			for (Module<Result, Argument> x : ms) {
				if (name.equals(x.getName())) {
					ms.remove(x);
					break;
				}
			}
			ms.add(module);
		}
	}

	/**
	 * 
	 * @param type
	 * @throws NoSuchModuleException 
	 */
	public T get(String type) throws NoSuchModuleException {
		List<T> ms = this.modules.get(type);
	     if (ms != null) {
	       if (ms.size() < 1){
	    	   logger.error("Type {} 不存在集合",type);
	    	   throw new NoSuchModuleException(type);
	       }
	       int index = ((AtomicInteger)this.indexes.get(type)).getAndIncrement();
	       synchronized (ms) {
	         return ms.get(index % ms.size());
	       }
	     }
	     logger.error("Type {} 集合为null",type);
	     throw new NoSuchModuleException(type);
	}

	public Configurator getConfigurator() {
		return this.context;
	}
	 
	/**
	 * 
	 * @param paramString
	 */
	protected abstract String getModuleClass(String paramString);

	public abstract String[] getModules();

	/**
	 * 
	 * @param paramString
	 */
	public abstract String getModuleType(String paramString);

	/**
	 * 
	 * @param type
	 */
	public List<T> getMoudles(String type) {
		return modules.get(type);
	}

	/**
	 * 
	 * @param type
	 * @param moudle
	 */
	public void remove(String type, T moudle) {

	}

	public void run() throws ModuleConstructException {
		boolean proxy = false;
		List<String> forRegModule = new ArrayList<String>();
		try {
			for (String module : getModules()) {
				logger.info("正在加载模块{}...",module);
				if("proxyclient".equals(module)){
					proxy = true;
					continue;
				}
				if(!"server".equalsIgnoreCase(module)
						&&!"proxy".equalsIgnoreCase(module)
						&&!"channel".equalsIgnoreCase(module)){
					forRegModule.add(module);
				}
				String clazzName = getModuleClass(module);
				logger.debug("class name is {}",clazzName);
				if (StringUtils.isBlank(clazzName))
					throw new NullPointerException(module
							+ " Module class name can't be blank!");
				String type = getModuleType(module);
				logger.debug("type is {}",type);
				if (StringUtils.isBlank(type))
					throw new NullPointerException(type
							+ " Module type  can't be blank!");
				@SuppressWarnings("unchecked")
				T m = (T)Creator.create(clazzName);
				assert (module != null);
				m.construct(module);
				add(m,module);

			}
			//增加代理服务器插件功能
			if(proxy){
				//向远程代理服务器注册
				String remoteAddr = ServerUtility.getProperty("module", "proxyclient", "url");
				ProxyArgument pa = new ObjectProxyArgument("proxyclient",remoteAddr);
				pa.setObject(forRegModule);//将本服务器的功能模块作为额外参数进行传递
				BizResult result = (BizResult)ServerUtility.submit("channel", pa);
				if(BizResult.TRUE.equals(result)){
					logger.info("注册远程代理服务器{}成功!",remoteAddr);
				}else{
					logger.error("注册远程代理服务器{}失败!",remoteAddr);
				}
			}
		} catch (CreatorException e) {
			logger.error("云架构应用模块启动时，创建Moudle出错",e);
		} catch (ConfiguratorException e) {
			logger.error("云架构应用模块启动时，注册远程代理服务失败",e);
		} catch (NoSuchModuleException e) {
			logger.error("云架构应用模块启动时，注册远程代理服务失败",e);
		} catch (ModuleException e) {
			logger.error("云架构应用模块启动时，注册远程代理服务失败",e);
		}

	}


}